﻿#include "../exercise.h"
#include <cmath>

enum class DataType {
    Float,
    Double,
};

/// @brief Tagged union 即标签化联合体，是联合体的一种常见应用。
///        Rust enum 在实现上就是标签化联合体。
struct TaggedUnion {
    DataType type;
    // NOTICE: struct/union 可以相互任意嵌套。
    union {
        float f;
        double d;
    };
};

// TODO: 将这个函数模板化用于 sigmoid_dyn
// float sigmoid(float x) {
//     return 1 / (1 + std::exp(-x));
// }

template<typename T>
T sigmoid(T x) {
    return static_cast<T>(1) / (static_cast<T>(1) + std::exp(-x));
}



// TaggedUnion sigmoid_dyn(TaggedUnion x) {
//     TaggedUnion ans{x.type};
//     // TODO: 根据 type 调用 sigmoid
//     return ans;
// }


TaggedUnion sigmoid_dyn(TaggedUnion x) {
    TaggedUnion ans;
    ans.type = x.type;  // 保持类型一致
    
    // 根据type调用对应的sigmoid
    switch (x.type) {
        case DataType::Float:
            ans.f = sigmoid(x.f);
            break;
        case DataType::Double:
            ans.d = sigmoid(x.d);
            break;
    }
    
    return ans;
}


// ---- 不要修改以下代码 ----
int main(int argc, char **argv) {
    TaggedUnion xf{DataType::Float};
    xf.f = 5.f;
    auto yf = sigmoid_dyn(xf);
    ASSERT(yf.type == DataType::Float, "type mismatch");
    ASSERT(yf.f == 1 / (1 + std::exp(-5.f)), "sigmoid float");

    TaggedUnion xd{DataType::Double};
    xd.d = 5.0;
    auto yd = sigmoid_dyn(xd);
    ASSERT(yd.type == DataType::Double, "type mismatch");
    ASSERT(yd.d == 1 / (1 + std::exp(-5.0)), "sigmoid double");
    return 0;
}



/*
加油

枚举、结构体、联合体


模板函数、及对应特化：
// 将sigmoid函数模板化
template<typename T>
T sigmoid(T x) {
    return static_cast<T>(1) / (static_cast<T>(1) + std::exp(-x));
}

// 针对float类型的特化（可选，但更明确）
template<>
float sigmoid(float x) {
    return 1.0f / (1.0f + std::exp(-x));
}

// 针对double类型的特化（可选，但更明确）
template<>
double sigmoid(double x) {
    return 1.0 / (1.0 + std::exp(-x));
}


3. sigmoid_dyn实现
TaggedUnion sigmoid_dyn(TaggedUnion x) {
    TaggedUnion ans;
    ans.type = x.type;  // 保持输入输出类型一致
    
    switch (x.type) {
        case DataType::Float:
            ans.f = sigmoid(x.f);    // 调用float版本
            break;
        case DataType::Double:
            ans.d = sigmoid(x.d);    // 调用double版本
            break;
    }
    
    return ans;
}
关键点：

类型一致性：输出的type字段与输入相同
类型安全：使用switch语句确保正确处理所有类型
正确访问联合体：根据类型访问对应的联合体成员
4. 标签化联合体的优势
这种模式在C++中很常见，特别是在需要：

处理多种数据类型但不想使用继承时
需要紧凑的内存布局时
与C语言接口交互时


虽然标签化联合体是有效的解决方案，但在现代C++中还有其他选择：

// 使用std::variant（C++17）
#include <variant>
using Number = std::variant<float, double>;

Number sigmoid_variant(Number x) {
    return std::visit([](auto value) -> Number {
        return sigmoid(value);
    }, x);
}

// 使用继承和多态
struct NumberBase {
    virtual ~NumberBase() = default;
    virtual std::unique_ptr<NumberBase> sigmoid() const = 0;
};

struct FloatNumber : NumberBase {
    float value;
    std::unique_ptr<NumberBase> sigmoid() const override {
        return std::make_unique<FloatNumber>(::sigmoid(value));
    }
};
测试验证
程序运行后会通过所有测试：

float类型的sigmoid计算正确
double类型的sigmoid计算正确
类型标签保持一致
计算结果符合数学期望
这个实现展示了如何在C++中使用标签化联合体来处理多态数据，同时保持了类型安全和代码清晰性。
*/